package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.enums.AttendEnums;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.feign.SysUserFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AttendGroupServiceImpl implements AttendGroupService {
    @Autowired
    AttendGroupMapper attendGroupMapper;
    @Autowired
    SysUserFeign sysUserFeign;
    @Autowired
    AttendGroupPartMapper attendGroupPartMapper;

    /**
     * 分页查询考勤分页数据，业务实现基本步骤如下：
     * 1. 查询当前企业是否初次使用
     * 2. 如果初次使用需要新增默认考勤组, 设置企业所有部门员工都采用默认考勤组 (调用系统微服务获取企业所有部门)
     * 3. 分页查询企业考勤组列表数据
     * 4. 遍历列表，获取企业考勤组中参与者数量
     *
     * 在第2步骤中, 需要根据查询当前企业下部门ID集合，用于将默认考勤组关联到部门。故需要在系统微服务中提供Feign接口逻辑为根据企业ID查询企业部门ID集合。
     * 在第4步骤中, 需要计算考勤组下关联的用户数量，故还需要提供根据部门ID查询部门员工数量的接口。
     */
    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {
        LambdaQueryWrapper<AttendGroup> attendGroupQw = new LambdaQueryWrapper<>();
        attendGroupQw.eq(AttendGroup::getCompanyId,CurrentUserHolder.get().getCompanyId());
        Integer count = attendGroupMapper.selectCount(attendGroupQw);

        if (count==0) {
            AttendGroup attendGroup= this.buildDefaultAttendGroup();
            attendGroupMapper.insert(attendGroup);

            List<Long> ids = sysUserFeign.queryDepartmentIds().getData();

            for (Long departmentId : ids) {
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectId(departmentId);
                attendGroupPart.setObjectType(AttendEnums.ATTEND_TYPE_YES.value());
                attendGroupPart.setAttendType(AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());
                attendGroupPartMapper.insert(attendGroupPart);
            }
        }

        LambdaQueryWrapper<AttendGroup> attendGroupQw1 = new LambdaQueryWrapper<>();
        attendGroupQw1.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());

        Page<AttendGroup> attendGroupPage = new Page(page, pageSize);
        attendGroupPage = attendGroupMapper.selectPage(attendGroupPage,attendGroupQw1);

        List<AttendGroup> records = attendGroupPage.getRecords();

        List<AttendGroupDTO> attendGroupDTOS = BeanHelper.copyWithCollection(records, AttendGroupDTO.class);
        for (AttendGroupDTO attendGroupDTO : attendGroupDTOS) {

            LambdaQueryWrapper<AttendGroupPart> attendGroupPartLambdaQueryWrapper = new LambdaQueryWrapper<>();
            attendGroupPartLambdaQueryWrapper.eq(AttendGroupPart::getAttendGroupId,attendGroupDTO.getId());
            List<AttendGroupPart> attendGroupPartList = attendGroupPartMapper.selectList(attendGroupPartLambdaQueryWrapper);

            List<Long> departmentIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                return attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_DEP.value();
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());

            List<Long> userIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                return attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_USER.value();
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());


            Integer depMemberCount = 0;
            if (CollectionUtil.isNotEmpty(departmentIds)) {
                depMemberCount = sysUserFeign.queryUserCountByDepartmentId(departmentIds).getData();
            }

            Integer number = depMemberCount + userIds.size();

            attendGroupDTO.setMemberNum(number);
        }
        return new PageResult<>(attendGroupPage.getTotal(), attendGroupPage.getPages(), attendGroupDTOS);

    }

    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {
        if (attendGroupDTO==null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //添加企业相关id
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setUpdateUserId(CurrentUserHolder.get().getCompanyId());

        if (attendGroupDTO.getWorkdays()!=null) {
            attendGroup.setWorkdays(StrUtil.join(",", attendGroupDTO.getWorkdays().toArray()));
        }

        List<String> necessaryTimeList = new ArrayList<>();
        List<String> unnecessaryTimeList = new ArrayList<>();

        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();
        for (AttendGroupPCExtraConfigDTO pcExtraConfigDTO : extraConfig) {
            String time = pcExtraConfigDTO.getSetDate();
            String date = DateUtil.format(new Date(Long.valueOf(time)), "yyyy-MM-dd");

            if (pcExtraConfigDTO.getRequiredAttend() == 1) {
                necessaryTimeList.add(date);
            }else if (pcExtraConfigDTO.getRequiredAttend() == 0){
                unnecessaryTimeList.add(date);
            }
        }
        attendGroup.setNecessaryTimeList(StrUtil.join(",",necessaryTimeList.toArray()));
        attendGroup.setNecessaryTimeList(StrUtil.join(",",unnecessaryTimeList.toArray()));

        attendGroupMapper.insert(attendGroup);
        this.saveAttendGroupPart(attendGroupDTO,attendGroup.getId());
    }

    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        AttendGroupPart attendGroupPart = this.queryAttendGroupPart(companyUserId, AttendEnums.ATTEND_OBJECT_TYPE_USER, AttendEnums.ATTEND_TYPE_YES);

        if (attendGroupPart==null) {
            List<Long> depIds = sysUserFeign.queryDepartmentsByUserId(companyUserId).getData();
            for (Long depId : depIds) {

                attendGroupPart = this.queryAttendGroupPart(depId,AttendEnums.ATTEND_OBJECT_TYPE_DEP, AttendEnums.ATTEND_TYPE_YES);
                if (attendGroupPart!=null) {
                    break;
                }
            }
        }

        if (attendGroupPart!=null) {
            AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupPart.getAttendGroupId());
            AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);

            String workdays = attendGroup.getWorkdays();

            if (StrUtil.isNotEmpty(workdays)) {
                attendGroupDTO.setWorkdays(Arrays.asList(attendGroup.getWorkdays().split(",")));
            }

            return attendGroupDTO;
        }else {
            throw new NcException(ResponseEnum.USER_NOT_MATCH_ATTENDGROUP);
        }


    }

    private AttendGroupPart queryAttendGroupPart(Long depId, AttendEnums attendObjectTypeDep, AttendEnums attendTypeYes) {
        LambdaQueryWrapper<AttendGroupPart> attendGroupPartLambdaQueryWrapper = new LambdaQueryWrapper<>();
        attendGroupPartLambdaQueryWrapper.eq(AttendGroupPart::getObjectId, depId);
        attendGroupPartLambdaQueryWrapper.eq(AttendGroupPart::getAttendType, attendTypeYes.value());
        attendGroupPartLambdaQueryWrapper.eq(AttendGroupPart::getObjectType, attendObjectTypeDep.value());

        List<AttendGroupPart> attendGroupParts = attendGroupPartMapper.selectList(attendGroupPartLambdaQueryWrapper);


        return attendGroupParts.isEmpty()?null:attendGroupParts.get(0);
    }

    //关联用户, 部门到该考勤组
    private void saveAttendGroupPart(AttendGroupDTO attendGroupDTO, Long id) {
        //需要参加考勤组的处理
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();
        participates.forEach(attendGroupPartDTO -> {
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartLambdaQueryWrapper = new LambdaQueryWrapper<>();
            attendGroupPartLambdaQueryWrapper.eq(AttendGroupPart::getObjectType,attendGroupPartDTO.getObjectType());
            attendGroupPartLambdaQueryWrapper.eq(AttendGroupPart::getObjectId,attendGroupPartDTO.getObjectId());

            attendGroupPartMapper.delete(attendGroupPartLambdaQueryWrapper);

            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setAttendGroupId(id);
            attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());
            attendGroupPart.setObjectType(attendGroupPartDTO.getObjectType());
            attendGroupPart.setObjectId(attendGroupPartDTO.getObjectId());

            attendGroupPartMapper.insert(attendGroupPart);
        });
        //不需要参加考勤组的处理
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();
        notParticipates.forEach(attendGroupPartDTO -> {
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getObjectId,attendGroupPartDTO.getObjectId());
            attendGroupPartQw.eq(AttendGroupPart::getObjectType,attendGroupPartDTO.getObjectType());
            attendGroupPartMapper.delete(attendGroupPartQw);

            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setAttendGroupId(id);
            attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_NO.value());
            attendGroupPart.setObjectType(attendGroupPartDTO.getObjectType());
            attendGroupPart.setObjectId(attendGroupPartDTO.getObjectId());
            attendGroupPartMapper.insert(attendGroupPart);
        });

    }

    //初始化考勤表
    private AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setAddressRange(400);
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setCreateTime(new Date());
        attendGroup.setLat(new BigDecimal("108.88995700000000000000"));
        attendGroup.setLng(new BigDecimal("34.37182600000000000000"));
        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");
        attendGroup.setLateMinutes(30);
        attendGroup.setWorkdays("1,1,1,1,1,0,0");
        return attendGroup;

    }
}
